﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BookShelf.Infrastructure.Domain
{
    public abstract class Entity<T, TKey> where T : Entity<T, TKey>
    {
        private int? oldHashCode;

        public abstract TKey ID { get; set; }

        public override bool Equals(object obj)
        {
            T other = obj as T;

            if (other == null)
                return false;

            //Handle comparing to objects with defualt or undefined ID values
            bool otherIsTransient = Equals(other.ID, default(TKey));
            bool thisIsTransient = Equals(this.ID, default(TKey));

            if (otherIsTransient && thisIsTransient)
                return ReferenceEquals(other, this);

            return other.ID.Equals(ID);
        }

        public virtual bool Equals(T other)
        {
            if (other == null)
                return false;

            return this.ID.Equals(other.ID);
        }

        public override int GetHashCode()
        {

            //This is done se we won't change the hash code
            if (oldHashCode.HasValue)
                return oldHashCode.Value;

            bool thisIsTransient = Equals(this.ID, default(TKey));

            //When we are transient, we use the base GetHashCode()
            //and remember it, so an instance can't change its hash code.
            if (thisIsTransient)
            {
                oldHashCode = base.GetHashCode();
                return oldHashCode.Value;
            }
            return ID.GetHashCode();
        }

        public static bool operator ==(Entity<T, TKey> x, Entity<T, TKey> y)
        {
            return Equals(x, y);
        }

        public static bool operator !=(Entity<T, TKey> x, Entity<T, TKey> y)
        {
            return !(x == y);
        }
    }
}
